#include "PreHeader.h"
#include "cFileRaw.h"

#include <io.h>
#include <assert.h>

#define DEFAULT_FILE_BUFFER_SIZE (8 * 1024)

tChar* cFileRaw::ms_dump_buffer = NULL;
tInt cFileRaw::ms_dump_size = 0;


cFileRaw::cFileRaw()
{
	m_fp = NULL;
	m_preRead = false;
	m_readBuffer = NULL;
	m_readPos = 0;
}

cFileRaw::~cFileRaw()
{
	Close();
}


tBool cFileRaw::Open(const tString& fullpath, eFileMode::TYPE mode, tBool alloc)
{
	m_mode = mode;
	m_fullpath = fullpath;

	m_preRead = false;

	if (mode & eFileMode::READ)
	{
		m_preRead = true;
	}

	if (m_preRead)
	{
		SAFE_DELETE_ARRAY(m_readBuffer);
		m_filesize = 0;
		m_readPos = 0;

		return cFileRaw::Dump(fullpath, mode, true, &m_readBuffer, m_filesize);
	}
	else
	{
		m_fp = fopen(fullpath.c_str(), eFileMode::ToChar(mode));
		if (m_fp == NULL) 
			return false;

		//m_filesize = _filelength(_fileno(m_fp));
		m_filesize = Size(m_fp);

		if (mode == eFileMode::AB)
            Seek(0, eFileSeek::END);
	}

	return true;
}


void cFileRaw::Close()
{
	if (m_fp)
	{
		fclose(m_fp);
		m_fp = NULL;
	}

	m_filesize = 0;

	SAFE_DELETE_ARRAY(m_readBuffer);
	m_readPos = 0;
}


tInt cFileRaw::Seek(tInt offset, eFileSeek::TYPE seek)
{
	if (m_preRead)
	{
		switch (seek)
		{
		case SEEK_CUR:
			m_readPos += offset; 
			if (m_readPos < 0)
			{
				assert( 0 );
				m_readPos = 0;
				return -1;
			}
			break; 

		case SEEK_END:
			m_readPos = m_filesize;
			break;

		case SEEK_SET:
			m_readPos = offset;
			break;

		default:
			return -1;
		}

		return m_readPos;
	}
	else
	{
		assert(m_fp);
		return fseek(m_fp, offset, seek);
	}
}

tUInt cFileRaw::Tell()
{
	if (m_preRead)
	{
		return m_readPos;
	}

    assert(m_fp);
    return ftell(m_fp);
}

tInt cFileRaw::Eof()
{
	if (m_preRead)
	{
		if (m_readPos >= m_filesize)
			return 1;
        else
            return 0;
	}
    return feof(m_fp);
}


tUInt cFileRaw::Read(void *data, tInt data_len)
{
	assert(m_mode & eFileMode::READ);

	if (m_readPos + data_len > m_filesize)
		data_len = m_filesize - m_readPos;

	if (data_len <= 0)
		return 0;

	memcpy(data, m_readBuffer + m_readPos, data_len);
	m_readPos += data_len;

	return data_len;
}


void cFileRaw::Write(void *data, tInt data_len)
{
	assert(m_mode & eFileMode::WRITE || m_mode & eFileMode::APPEND);
	fwrite(data, data_len, 1, m_fp);
}


tChar* cFileRaw::Gets(tChar *str, tInt str_len)
{
	assert(m_mode & eFileMode::READ);

	if (m_readPos >= m_filesize)
		return NULL;

	tInt nRead = 0;
	tChar * pBuf = str;
	const tChar * p = (const tChar*)(m_readBuffer + m_readPos);
	while( ('\0' != *p ) && ('\n' != *p ) && (m_readPos + nRead <= m_filesize-1) && (nRead < str_len-1) )
	{
		*pBuf++ = *p++;
		nRead++;
	}

	nRead++;

	if( '\n' == *p  )
	{
		*pBuf = '\n';
		*(pBuf+1) = '\0';
	}	
	else
		*pBuf = '\0';

	m_readPos += nRead;

	return str;
}

void cFileRaw::Puts(const tChar *str)
{
	assert(m_mode & eFileMode::WRITE || m_mode & eFileMode::APPEND);
	fputs(str, m_fp);
}



//-------------------------------------------------------------------------------------------------

void cFileRaw::Init()
{
	ms_dump_size = DEFAULT_FILE_BUFFER_SIZE;
	if (ms_dump_size)
		ms_dump_buffer = new tChar[ms_dump_size];
}

void cFileRaw::Finish()
{
	SAFE_DELETE_ARRAY(ms_dump_buffer);
}


tBool cFileRaw::Access(const tString& fullpath)
{
	if (access(fullpath.c_str(), 0) == 0)
		return true;
	return false;
}


tBool cFileRaw::Dump(const tString& fullpath, eFileMode::TYPE mode, tBool alloc, OUT tChar** pp_buffer, OUT tInt& size)
{
	FILE* fp = fopen(fullpath.c_str(), eFileMode::ToChar(mode));
    if (fp == 0) 
    {
		return false;
    }

	//size = _filelength(_fileno(fp));
	size = Size(fp);

	if (alloc)
	{
		*pp_buffer = new tChar[size];
	}
	else
	{
		if (size > ms_dump_size)
		{
			SAFE_DELETE_ARRAY(ms_dump_buffer);
			ms_dump_buffer = new tChar[size];
			ms_dump_size = size;
		}
		*pp_buffer = ms_dump_buffer;
	}

	tInt cur_read_size = 0;
	tInt buffer_size = size;
	tBool result = true;

	while (!feof(fp))
	{
		tInt read_size = (tInt)fread(*pp_buffer + cur_read_size, 1, buffer_size, fp);

		buffer_size -= read_size;
		cur_read_size += read_size;

		if (buffer_size <= 0)
			break;

		if (ferror(fp))
		{
			result = false;
			break;
		}
	}

	fclose(fp);

	if (!result)
	{
		if (alloc)
		{
			SAFE_DELETE_ARRAY(*pp_buffer);
		}
		else
			*pp_buffer = NULL;
		size = 0;

		return false;
	}

	if (buffer_size > 0)
		memset(*pp_buffer + cur_read_size, 0, buffer_size);

	size = cur_read_size;

	return true;
}

tInt cFileRaw::Size(FILE* fp)
{
	fseek(fp, 0l, SEEK_END);  
	tInt length = ftell(fp);  
	fseek(fp, 0l, SEEK_SET);

	return length;
}